#ifndef POINT3D_H_
#define POINT3D_H_

#include <math.h>

class Point3D {
	public:
		double x, y, z;

		Point3D() : x(0), y(0), z(0) {}
		Point3D(double x, double y, double z) : x(x), y(y), z(z) {}

		Point3D operator+(const Point3D& other) const {
			return Point3D(x + other.x, y + other.y, z + other.z);
		}

		Point3D operator-(const Point3D& other) const {
			return Point3D(x - other.x, y - other.y, z - other.z);
		}

		Point3D operator*(const double scale) const {
			return Point3D(x * scale, y * scale, z * scale);
		}

		Point3D operator/(const double scale) const {
			double invScale = 1 / scale;
			return Point3D(x * invScale, y * invScale, z * invScale);
		}

		Point3D& operator+=(const Point3D& other) {
			x += other.x;
			y += other.y;
			z += other.z;
			return *this;
		}

		Point3D& operator-=(const Point3D& other) {
			x -= other.x;
			y -= other.y;
			z -= other.z;
			return *this;
		}

		Point3D& operator*=(const double scale) {
			x *= scale;
			y *= scale;
			z *= scale;
			return *this;
		}

		Point3D& operator/=(const double scale) {
			double invScale = 1 / scale;
			x *= invScale;
			y *= invScale;
			z *= invScale;
			return *this;
		}

		double dot(const Point3D other) const {
			return x * other.x +
					y * other.y +
					z * other.z;
		}

		Point3D cross(const Point3D& other) const {
			return Point3D(
					y * other.z - z * other.y,
					z * other.x - x * other.z,
					x * other.y - y * other.x
			);
		}

		double magnitude() const {
			return sqrt(x * x + y * y + z * z);
		}

		double distance(const Point3D& other) const {
			return sqrt(
					(x - other.x) * (x - other.x) +
					(y - other.y) * (y - other.y) +
					(z - other.z) * (z - other.z)
			);
		}

		double distanceSquared(const Point3D& other) const {
			return (
					(x - other.x) * (x - other.x) +
					(y - other.y) * (y - other.y) +
					(z - other.z) * (z - other.z)
			);
		}

		void normalize() {
			double d = 1 / sqrt(x * x + y * y + z * z);
			x *= d;
			y *= d;
			z *= d;
		}

		void normalizeB() {
			double d = 1 / (x + y + z);
			x *= d;
			y *= d;
			z *= d;
		}
};

#endif
